﻿///
/// Developer: Jirapong Nanta (jirapong.nanta@gmail.com)
/// Date: 11 July 2008
/// Copyright @ 2008 www.awsstudio.net
///
using System;
using System.AWSServices.S3.S3SoapProxy;
using System.AWSServices.Shared;
using System.Text;
using System.Diagnostics;
using System.Security.Authentication;
using System.Collections.Generic;

namespace System.AWSServices.S3
{
    public class S3Client : IDisposable
    {
        internal static readonly string SERVICE_NAME = "AmazonS3";

        #region Fields
        private AmazonS3 m_AmazonS3 = null;
        private bool m_UseSSL = true;
        private string m_Port = "443";

        private List<Bucket> m_Buckets;
        #endregion

        #region Constructor
        public S3Client()
        {
            Server = "s3.amazonaws.com";
        }

        public S3Client(string accessKey, string secretKey)
            : this()
        {
            this.AccessKey = accessKey;
            this.SecretKey = secretKey;
        }

        public S3Client(string accessKey, string secretKey, bool useSSL)
            : this(accessKey, secretKey)
        {
            this.UseSSL = useSSL;
        }
        #endregion

        #region Automatic Properties
        public string AccessKey { get; set; }
        public string SecretKey { get; set; }
        public string Server { get; set; }
        public string Port { get; set; }
        public bool IsConnected { get; private set; }
        internal bool IsDirty { get; set; }
        #endregion

        #region Internal Properties
        internal AmazonS3 AmazonS3Soap
        {
            get
            {
                return m_AmazonS3;
            }
        }
        #endregion

        #region Properties
        public bool UseSSL
        {
            get
            {
                return m_UseSSL;
            }
            set
            {
                if (m_UseSSL != value)
                {
                    m_UseSSL = value;
                    m_Port = value ? "443" : "80";
                }
            }
        }
        // TODO: don't know what to do about it yet
        //public bool Persistent { get; set; } // kind of leave WS connection open 
        // TODO: Support Proxy
        //public string Proxy { get; set; } 
        //public string Host { get; set; } // If Proxy set, host is required

        public List<Bucket> Buckets
        {
            get
            {
                // TODO: some cached here
                if (m_Buckets == null || IsDirty)
                {
                    m_Buckets = new List<Bucket>();

                    DateTime timestamp = AWSSecurity.TimeStamp;
                    string signature = AWSSecurity.CreateSignature(SecretKey, SERVICE_NAME, "ListAllMyBuckets", timestamp);
                    ListAllMyBucketsResult result = null;
                    result = m_AmazonS3.ListAllMyBuckets(AccessKey, timestamp, true, signature);
                    foreach (var item in result.Buckets)
                    {
                        m_Buckets.Add(new Bucket() {Name = item.Name, CreationDate = item.CreationDate });
                        Debug.WriteLine("Bucket added: " + item.Name);
                    }
                }

                return m_Buckets;
            }
        }
        #endregion

        #region Methods : Connection
        public bool EstablishConnection()
        {
            if (string.IsNullOrEmpty(AccessKey)) throw new NullReferenceException("AccessKey is neccessary for connection, visit http://aws.amazon.com to obtains the key.");
            if (string.IsNullOrEmpty(SecretKey)) throw new NullReferenceException("SecretKey is neccessary for connection, visit http://aws.amazon.com to obtains the key.");

            if (IsConnected) return true;

            IsConnected = false;

            //connect to Soap
            m_AmazonS3 = new AmazonS3();
            m_AmazonS3.Url = string.Format(@"http{0}://{1}:{2}/soap/", UseSSL ? "s" : "", Server, Port);

            Debug.WriteLine(string.Format("Connecting to S3 server at '{0}'.", m_AmazonS3.Url));

            DateTime timestamp = AWSSecurity.TimeStamp;
            string signature = AWSSecurity.CreateSignature(SecretKey, SERVICE_NAME, "ListAllMyBuckets", timestamp);
            ListAllMyBucketsResult result = null;
            try
            {
                result = m_AmazonS3.ListAllMyBuckets(AccessKey, timestamp, true, signature);
                if (m_Buckets == null) m_Buckets = new List<Bucket>();
                foreach (var item in result.Buckets)
                {
                    m_Buckets.Add(new Bucket() { Name = item.Name, CreationDate = item.CreationDate });
                    Debug.WriteLine("Bucket added: " + item.Name);
                }

                IsDirty = false;
            }
            catch (System.Web.Services.Protocols.SoapException sEx)
            {
                if (sEx.Code.Name == "Client.SignatureDoesNotMatch")
                    throw new AuthenticationException("Your AWS Key and/or Secret Key were wrong, try to check with http://aws.amazon.com.", sEx);
                else
                    throw;
            }

            IsConnected = (result != null);

            Debug.WriteLine("Connection is " + (IsConnected ? "success" : "fail"));

            return IsConnected;
        }

        public void Disconnect()
        {
            if (!IsConnected) return;

            if (m_AmazonS3 != null)
            {
                m_AmazonS3.Dispose();
                m_AmazonS3 = null;
            }

            IsConnected = false;
        }
        #endregion

        #region Methods : Bucket
        #endregion

        #region Methods : Object
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (m_AmazonS3 != null) m_AmazonS3.Dispose();
        }

        #endregion

    }
}
